﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Mail;
using System.Text;
using Mindfor.Web.Config;
using Mindfor.Web.Data;
using NHibernate;
using NHibernate.Linq;
using System.Threading;

namespace Mindfor.Web.Modules.Mail
{
	/// <summary>
	/// Enalbes mail sending in site.
	/// </summary>
	public class MailModule : ModuleBase
	{
		BackgroundWorker m_mailWorker;

		/// <summary>
		/// Registers module. For example, custom routes.
		/// </summary>
		/// <param name="info">Registration data.</param>
		public override void Register(ModuleRegistrationData info)
		{
			base.Register(info);
			
			m_mailWorker = new BackgroundWorker();
			m_mailWorker.WorkerSupportsCancellation = true;
			m_mailWorker.DoWork += MailSenderWork;
			m_mailWorker.RunWorkerAsync();
		}

		/// <summary>
		/// Called when application is ending.
		/// </summary>
		public override void Unload()
		{
			if (m_mailWorker != null)
			{
				m_mailWorker.CancelAsync();
				m_mailWorker = null;
			}
			base.Unload();
		}

		/// <summary>
		/// Performs mail send actions.
		/// </summary>
		private void MailSenderWork(object sender, DoWorkEventArgs e)
		{
			// consts
			const int maxPortionSize = 20;
			const int waitTime = 1000 * 60 * 1; // 1 min

			// secure work
			try
			{
				// create smtp client
				SmtpClient smtp = new SmtpClient();
				smtp.EnableSsl = CmsConfig.Default.Mail.EnableSsl;
				smtp.Timeout = 30000;

				// work forever
				while (!m_mailWorker.CancellationPending)
				{
					using (ISession data = CmsApplication.DataProvider.SessionFactory.OpenSession())
					{
						// get portion
						List<MailQueue> items = data.Query<MailQueue>().GetWaitingQueueItems(maxPortionSize).ToList();
						if (items.Count > 0)
						{
							using (ITransaction t = data.BeginTransaction())
							{
								// send portion
								foreach (MailQueue item in items)
								{
									smtp.Send(item.ToMailMessage());
									item.SendDate = DateTime.UtcNow;
									data.Update(item);
								}
								t.Commit();
							}
						}
					}

					// wait
					Thread.Sleep(waitTime);
				}
			}
			catch
			{
			}
		}
	}
}
